//
//  RxFeedbackTest2ViewController.swift
//  iOS-RxSwift-Tutorials_Example
//
//  Created by mengru.tian on 2020/9/24.
//  Copyright © 2020 CocoaPods. All rights reserved.
//

import UIKit
import RxSwift
import RxFeedback
import RxCocoa

class RxFeedbackTest2ViewController: UIViewController {
    
    //用户名输入框、以及验证结果显示标签
    @IBOutlet weak var usernameOutlet: UITextField!
    @IBOutlet weak var usernameValidationOutlet: UILabel!
     
    //密码输入框、以及验证结果显示标签
    @IBOutlet weak var passwordOutlet: UITextField!
    @IBOutlet weak var passwordValidationOutlet: UILabel!
     
    //重复密码输入框、以及验证结果显示标签
    @IBOutlet weak var repeatedPasswordOutlet: UITextField!
    @IBOutlet weak var repeatedPasswordValidationOutlet: UILabel!
     
    //注册按钮
    @IBOutlet weak var signupOutlet: UIButton!
     
    //注册时的活动指示器
    @IBOutlet weak var signInActivityIndicator: UIActivityIndicatorView!
     
    let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()

        title = "63.RxFeedback架构2：一个用户注册样例"
        view.backgroundColor = .white
        
        test()
    }
    
    func test() {
        //GitHub网络请求服务
        let networkService = GitHubNetworkService3()
         
        //用户注册服务
        let signupService = GitHubSignupService()
         
         Driver.system(
                   //初始状态
                   initialState: State.empty,
                   //各个事件对状态的改变
                   reduce: { (state, event) -> State in
                       switch event {
                       case .usernameChanged(let value):
                           var result = state
                           result.username = value
                           result.signupResult = nil //防止弹出框重复弹出
                           return result
                       case .passwordChanged(let value):
                           var result = state
                           result.password = value
                           //验证密码
                           result.passwordValidationResult =
                               signupService.validatePassword(result.password ?? "")
                           //验证密码重复输入
                           if result.repeatedPassword != nil {
                               result.repeatedPasswordValidationResult =
                                   signupService.validateRepeatedPassword(
                                       result.password ?? "",
                                       repeatedPassword: result.repeatedPassword ?? ""
                               )
                           }
                           result.signupResult = nil
                           return result
                       case .repeatedPasswordChanged(let value):
                           var result = state
                           result.repeatedPassword = value
                           //验证密码重复输入
                           result.repeatedPasswordValidationResult =
                               signupService.validateRepeatedPassword(
                                   result.password ?? "",
                                   repeatedPassword: result.repeatedPassword ?? ""
                               )
                           result.signupResult = nil
                           return result
                       case .usernameValidated(let value):
                           var result = state
                           result.usernameValidationResult = value
                           result.signupResult = nil
                           return result
                       case .signup:
                           var result = state
                           result.startSignup = true
                           result.signupResult = nil
                           return result
                       case .signupResponse(let value):
                           var result = state
                           result.startSignup = false
                           result.signupResult = value
                           return result
                       }
                   },
                   feedback:
                       //UI反馈
                       bind(self) { me, state in
                           //状态输出到页面控件上
                           let subscriptions = [
                                
                               //用户名验证结果绑定
                               state.map{ $0.usernameValidationResult }
                                   .drive(me.usernameValidationOutlet.rx.validationResult),
                               //密码验证结果绑定
                               state.map{ $0.passwordValidationResult }
                                   .drive(me.passwordValidationOutlet.rx.validationResult),
                               //重复密码验证结果绑定
                               state.map{ $0.repeatedPasswordValidationResult }
                                   .drive(me.repeatedPasswordValidationOutlet.rx.validationResult),
                               //注册按钮是否可用
                               state.map{ $0.usernameValidationResult.isValid &&
                                          $0.passwordValidationResult.isValid &&
                                          $0.repeatedPasswordValidationResult.isValid}
                                   .drive(onNext: { valid  in
                                       me.signupOutlet.isEnabled = valid
                                       me.signupOutlet.alpha = valid ? 1.0 : 0.3
                                   }),
                               //活动指示器绑定
                               state.map{ $0.startSignup }
                                   .drive(me.signInActivityIndicator.rx.isAnimating),
                               //注册结果显示
                               state.map{ $0.signupResult }
                                   .filter{ $0 != nil }
                                   .drive(onNext: { result  in
                                       me.showMessage("注册" + (result! ? "成功" : "失败") + "!")
                                   })
                           ]
                           //将 UI 事件变成Event输入到反馈循环里面去
                           let events = [
                               //用户名输入
                               me.usernameOutlet.rx.text.orEmpty.changed
                                   .asSignal().map(Event.usernameChanged),
                               //密码输入
                               me.passwordOutlet.rx.text.orEmpty.changed
                                   .asSignal().map(Event.passwordChanged),
                               //重复密码输入
                               me.repeatedPasswordOutlet.rx.text.orEmpty.changed
                                   .asSignal().map(Event.repeatedPasswordChanged),
                               //注册按钮点击
                               me.signupOutlet.rx.tap
                                   .asSignal().map{ _ in Event.signup },
                           ]
                           return Bindings(subscriptions: subscriptions, events: events)
                       },
                       //非UI的自动反馈（用户名验证）
                       react(request: { $0.username }, effects: { username  in
                           return signupService.validateUsername(username)
                               .asSignal(onErrorRecover: { _ in .empty() })
                               .map(Event.usernameValidated)
                       })
                       //非UI的自动反馈（用户注册）
            ,react(request: { $0.signupData }, effects: { signupData in
                return networkService.signup(signupData!.username!, password: signupData!.password!)
                               .asSignal(onErrorRecover: { _ in .empty() })
                               .map(Event.signupResponse)
                       })
                   )
                   .drive()
                   .disposed(by: disposeBag)
    }
    
    //详细提示框
    func showMessage(_ message: String) {
        let alertController = UIAlertController(title: nil,
                                    message: message, preferredStyle: .alert)
        let okAction = UIAlertAction(title: "确定", style: .cancel, handler: nil)
        alertController.addAction(okAction)
        self.present(alertController, animated: true, completion: nil)
    }
}

extension RxFeedbackTest2ViewController {
    
    //状态
    struct State {
        
        struct SignupData:Equatable {

            var username: String? //用户名
            var password: String? //密码
        }
        
        var username: String? //用户名
        var password: String? //密码
        var repeatedPassword: String? //再出输入密码
        var usernameValidationResult: ValidationResult //用户名验证结果
        var passwordValidationResult: ValidationResult //密码验证结果
        var repeatedPasswordValidationResult: ValidationResult //重复密码验证结果
        var startSignup: Bool //开始注册
        var signupResult: Bool? //注册结果
         
        //用户注册信息（只有开始注册状态下才有数据返回）
        var signupData: SignupData? {
            return startSignup ? SignupData(username: username ?? "", password: username ?? "") : nil
        }
         
        //返回初始化状态
        static var empty: State {
            return State(username: nil, password: nil, repeatedPassword: nil,
                         usernameValidationResult: ValidationResult.empty,
                         passwordValidationResult: ValidationResult.empty,
                         repeatedPasswordValidationResult: ValidationResult.empty,
                         startSignup: false, signupResult: nil)
        }
    }
     
    //事件
    enum Event {
        case usernameChanged(String) //用户名输入
        case passwordChanged(String) //密码输入
        case repeatedPasswordChanged(String) //重复密码输入
        case usernameValidated(ValidationResult) //用户名验证结束
        case signup //用户注册
        case signupResponse(Bool) //注册响应
    }
}
